import time
from flask import Blueprint, request, Response, jsonify
from concurrent.futures import ThreadPoolExecutor
from orm import Request, Status, Log
from peewee import fn

# 请求队列超出大小限制将抛出此异常
class RequestException(Exception):
    def __init__(self, err='请求队列超出大小限制'):
        Exception.__init__(self, err)


class mainMachine:
    main_status = 2  # 表示主机状态，制冷1、制热2
    is_standby = 1  # 记录是否待机，待机1、运行0
    num = 3  # 能够同时运行的空调资源数
    requestList = []  # 这一秒的请求列表
    flag = True  # 循环标志
    servertime = 20 # 资源紧张时，每台从机可以用2分钟轮转
    def run(self):
        while self.flag:

            self.relese()               # 将服务时长超过2分钟的空调关机并产生一条详单
            self.get_request()
            self.resolve_request()
            time.sleep(1/6)

    def exit(self):
        Status.update(speed=0).execute()
        self.flag = False

    def judge_status(self):  # 判断主机是否应该处于待机状态
        #   如果有请求表中有请求则应该处于待机，否则应该运行
        self.is_standby = 0 if Request.select().count() > 0 else 1

    def init(self):  # 初始化请求表
        # 删除所有请求
        Request.delete().execute()


    def push(self, *arg):  # 将请求加入待处理队列,超过上限抛出异常
        init_count = Status.select().where(Status.speed!=0).count()
        for item in arg:
            status = Status.get(Status.id == item.slave_id)
            if item.speed != 0 and status.speed==0 :
                # 如果是开机请求，则判别是否还有空调资源可用
                if init_count < self.num:
                    # # 删除数据库中对应的数据
                    self.requestList.append(item)
                    init_count+=1
                else:
                    # 空调资源用完
                    raise RequestException
            else:
                # 关机请求
                self.requestList.append(item)
                # Request.delete_by_id(item.id)   #   将对应请求删除

    def get_request(self):  # 获得所有待处理请求队列
        try:
            self.requestList = []  # 清空队列
            self.push(*[item for item in self.power_first()])  # 填入开关机请求，开关机请求优先
            self.push(*[
                item for item in Request.select().order_by(-Request.speed)
            ])
            # self.push(*[item for item in Request.select()])
        except RequestException:
            return

    def relese(self):
        try:
            run_slave = Status.select().where(Status.speed!=0)
            speed_1 = Status.select().where(Status.speed==1)
            speed_2 = Status.select().where(Status.speed==2)
            # speed_3 = Status.select().where(Status.speed==3)
            is_open = Status.select().where(Status.open!=0).count()
            need = is_open-self.num
            for status in speed_1:
                if need>0 and run_slave.count()>=self.num:  
                    if (time.time() - time.mktime(time.strptime(str(status.start_time),"%Y-%m-%d %H:%M:%S"))) >=self.servertime:
                            status.speed = 0
                            status.save()
                            # 关机产生详单
                            Log(slave_id=status.id,
                                card_id=status.card_id,
                                cur_temp=status.cur_temp,
                                target_temp=status.target_temp,
                                speed=status.speed,
                                res_time=time.strftime('%Y-%m-%d %H:%M:%S')).save()
                            # 将数据库中Request表中重复的请求删除
                            # Request.delete().where((Request.slave_id == status.id)&(Request.speed==2)).execute()   #   将请求对应的从机号对应的所有请求删除
                            need-=1     
                else:break
            for status in speed_2:
                if need>0 and run_slave.count()>=self.num:  
                    if (time.time() - time.mktime(time.strptime(str(status.start_time),"%Y-%m-%d %H:%M:%S"))) >=self.servertime:
                            status.speed = 0
                            status.save()
                            # 关机产生详单
                            Log(slave_id=status.id,
                                card_id=status.card_id,
                                cur_temp=status.cur_temp,
                                target_temp=status.target_temp,
                                speed=status.speed,
                                res_time=time.strftime('%Y-%m-%d %H:%M:%S')).save()
                            # 将数据库中Request表中重复的请求删除
                            # Request.delete().where((Request.slave_id == status.id)&(Request.speed==2)).execute()   #   将请求对应的从机号对应的所有请求删除
                            need-=1     
                else:break       

                                       
        except Exception as e:
            pass



        # try:
        #     run_slave = Status.select().where(Status.speed!=0)
        #     is_open = Status.select().where(Status.open!=0).count()
        #     # 如果资源超出现有资源（默认3）,将服务时长超过3分钟的从机停机 
        #     if is_open > self.num and run_slave.count()>=self.num:
        #         max_speed = max(Request.select(fn.Max(Request.speed)).scalar(),Status.select(fn.Max(Status.speed)).scalar())
        #         for status in run_slave:
        #             # 服务超过120分钟关机释放资源
        #             # if (time.time() - time.mktime(time.strptime(str(status.start_time),"%Y-%m-%d %H:%M:%S"))) >=self.servertime and int(status.speed)< max_speed :
        #             if (time.time() - time.mktime(time.strptime(str(status.start_time),"%Y-%m-%d %H:%M:%S"))) >=self.servertime:
        #                     status.speed = 0
        #                     status.save()
        #                     # 关机产生详单
        #                     Log(slave_id=status.id,
        #                         card_id=status.card_id,
        #                         cur_temp=status.cur_temp,
        #                         target_temp=status.target_temp,
        #                         speed=status.speed,
        #                         res_time=time.strftime('%Y-%m-%d %H:%M:%S')).save()
        #                     # 将数据库中Request表中重复的请求删除
        #                     Request.delete().where(Request.slave_id == status.id).execute()   #   将请求对应的从机号对应的所有请求删除          
        # except Exception as e:
        #     pass      

    def resolve_request(self):  # 处理队列中的请求
        # print("resolve!")
        for item in self.requestList:
            status = Status.get(Status.id == item.slave_id)
            # 忽略重复请求
            if item.temp==status.target_temp and item.speed==status.speed:
                break
            if self.main_status == 1 and item.temp >= 18 and item.temp <= 28:  # 处于制冷模式并且温度在可调控范围内
                if status.cur_temp < item.temp:  # 从机当前温度低于请求温度则风速调0,等待温度回升
                    status.target_temp = item.temp
                    status.speed = 0
                    status.save()
                    # 关机产生详单
                    Log(slave_id=item.slave_id,
                        card_id=status.card_id,
                        cur_temp=status.cur_temp,
                        target_temp=item.temp,
                        speed=0,
                        res_time=time.strftime('%Y-%m-%d %H:%M:%S')).save()
                else:
                    status.target_temp = item.temp
                    if status.speed==0 and item.speed != 0 :
                        # 如果是开机服务则记录开机时间
                        status.start_time = time.strftime("%Y-%m-%d %H:%M:%S")
                    status.speed = item.speed
                    status.save()
                    item.save()
                    # 请求服务产生详单
                    Log(slave_id=item.slave_id,
                        card_id=status.card_id,
                        cur_temp=status.cur_temp,
                        target_temp=item.temp,
                        speed=item.speed,
                        res_time=time.strftime('%Y-%m-%d %H:%M:%S')).save()
                    
            elif self.main_status == 2 and item.temp >= 18 and item.temp <= 25:
                if status.cur_temp >= item.temp:  # 从机当前温度高于目标温度则风速调0,等待温度下降
                    status.target_temp = item.temp
                    status.speed = 0
                    status.save()
                    # 关机产生详单
                    Log(slave_id=item.slave_id,
                        card_id=status.card_id,
                        cur_temp=status.cur_temp,
                        target_temp=status.target_temp,
                        speed=status.speed,
                        res_time=time.strftime('%Y-%m-%d %H:%M:%S')).save()
                    
                else:
                    status.target_temp = item.temp
                    if status.speed==0 and item.speed != 0 :
                        status.start_time = time.strftime("%Y-%m-%d %H:%M:%S")                        
                    status.speed = item.speed
                    status.save()
                    # item.time = time.strftime("%Y-%m-%d %H:%M:%S")
                    # 请求服务产生详单
                    item.save()
                    Log(slave_id=item.slave_id,
                        card_id=status.card_id,
                        cur_temp=status.cur_temp,
                        target_temp=item.temp,
                        speed=item.speed,
                        res_time=time.strftime('%Y-%m-%d %H:%M:%S')).save()
                    
            # 将数据库中Request表中重复的请求删除
            Request.delete_by_id(item.id)   #   将对应请求删除
            # Request.delete().where(Request.slave_id == item.slave_id).execute()   #   将请求对应的从机号对应的所有请求删除            


    def power_first(self):
        for item in Request.select():
            status = Status.get(Status.id == item.slave_id)
            if status.speed == 0 and item.speed > 0:  # 开机请求
                yield item
            elif item.speed == 0 and status.speed !=0 :  # 关机请求
                yield item


machine = Blueprint('machine', __name__)
executor = ThreadPoolExecutor(1)
m = mainMachine()


@machine.route("/open")
def open():
    m.flag = True
    m.init()
    executor.submit(m.run)
    return Response('ok', 200)


@machine.route("/close")
def close():
    m.exit()
    return Response('ok', 200)


@machine.route('/info')
def status():
    return jsonify({
        'status': m.main_status,
        'power': m.num,
        'standby': m.is_standby
    })


@machine.route('/set', methods=['GET', 'POST'])
def setting():
    if request.method == "POST":
        m.num = int(request.json['power'])
        m.main_status = int(request.json['status'])
    m.init()
    return 'ok'
